/*
Kakine
ActionScript Framework
Copyright © 2011, PUNY, LLC.

This file is part of KAKINE.

KAKINE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

KAKINE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KAKINE.  If not, see <http://www.gnu.org/licenses/>.
*/ 
package com.puny.mvc.views.platformer.movieclips
{
	import com.puny.utils.CollisionPt;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public class VerletCharacterView extends CharacterView {
		public static const ON_GROUND:String = "on ground";
		public static const OFF_GROUND:String = "off ground";
		private var _force:Point = new Point();
		private var _pt:Point = new Point();
		private var _onGround:Boolean;
		private var _left:CollisionPt;
		private var _right:CollisionPt;
		private var _top:CollisionPt;
		private var _bottom:CollisionPt;
		private var _collisions:Array = new Array();
		private var _consistency:int;
		
		public function VerletCharacterView() {
			super();
		}
		
		public function get consistency():int {
			return _consistency;
		}
		
		public function set consistency(value:int):void {
			_consistency = value;
		}
		
		override public function beforeReady():void {
			_left = new CollisionPt(CollisionPt.FROM_LEFT);
			_right = new CollisionPt(CollisionPt.FROM_RIGHT);
			_top = new CollisionPt(CollisionPt.FROM_TOP);
			_bottom = new CollisionPt(CollisionPt.FROM_BOTTOM);
			_collisions.push(_left);
			_collisions.push(_right);
			_collisions.push(_top);
			_collisions.push(_bottom);
			super.beforeReady();
			stopAt(x,y);
		}
		
		override public function afterClose():void {
			super.afterClose();
			while(_collisions.length > 0) {
				_collisions.pop();
			}
			_left = null;
			_right = null;
			_top = null;
			_bottom = null;
		}

		public function isStoppingHorizontaly():Boolean {
			return (x == _pt.x);
		}
		
		public function isStoppingVertically():Boolean {
			return (y == _pt.y);
		}
		
		public function addForce(pt:Point):void {
			_force = _force.add(pt);
		}
		
		public function verlet():void {
			velocity.x = x - _pt.x + _force.x;
			velocity.y = y - _pt.y + _force.y;
			
//			velocity.x = velocity.x > 30 ? 30 : ((velocity.x < -30)? -30 : velocity.x);
//			velocity.y = velocity.y > 100 ? 100 : ((velocity.y < -30)? -30 : velocity.y);
		}
		
		override public function set collisionArea(value:DisplayObject):void {
			super.collisionArea = value;
			stopAt(x,y);
		}
		public function collision(obj:ObjectView):CollisionPt {
			var v:Point = velocity.clone();
			v = v.subtract(obj.velocity);

			if (_left == null) {
				_top = new CollisionPt(CollisionPt.FROM_TOP);
				_left = new CollisionPt(CollisionPt.FROM_LEFT);
				_right = new CollisionPt(CollisionPt.FROM_RIGHT);
				_bottom = new CollisionPt(CollisionPt.FROM_BOTTOM);
				_collisions.push(_left);
				_collisions.push(_right);
				_collisions.push(_top);
				_collisions.push(_bottom);
			}
			var rect:Rectangle = CollisionPt.collisionRect(this,obj);
			
			_top.check(this,obj,v,rect);
			if (obj is InvisibleHalfPlatformView) {
				if (_top.time == Infinity) {
					return null;
				} else if (obj.y > this.y + this.height) {
					return _top;
				} else {
					return null;
				}
			} else {
				_left.check(this,obj,v,rect);
				_right.check(this,obj,v,rect);
				_bottom.check(this,obj,v,rect);
	
				_collisions.sortOn("time",Array.NUMERIC);
				if (_collisions[0].time == Infinity) {
					return null;
				}
			}
			return _collisions[0];
		}

		public function stopAt(stopX:Number,stopY:Number):void {
			_pt.x = stopX
			_pt.y = stopY;
			_force.x = 0;
			_force.y = 0;
		}
		
		public function shift(sx:Number, sy:Number):void {
			x += sx;
			y += sy;
			_pt.x += sx;
			_pt.y += sy;
		}
		
		public function stopHorizontal():void {
			_pt.x = x;
			_force.x = 0;
		}
		
		public function moveTo(tx:Number,ty:Number):void {
			var tmp:String;
			_pt.x = x;
			_pt.y = y;
			onGround = ty < 1 && velocity.y > 0;
			x += velocity.x * tx;
			y += velocity.y * ty;
			if (onGround) {
				//dynamic frictions
				if (velocity.x > -.5 && velocity.x < .5) {
					velocity.x = 0;
					_pt.x = x;
				}
				_force.x = int(-20 * velocity.x) / 100;
			} else {
				if (velocity.x > -.5 && velocity.x < .5) {
					velocity.x = 0;
					_pt.x = x;
				}
				_force.x = int(-20 * velocity.x) / 100;
			}
			_force.y = 0;
		}

		public function get onGround():Boolean {
			return _onGround;
		}
		
		public function faceToLeft():void {
			if (scaleX < 0) {
				scaleX = -scaleX;
			}
		}
		
		public function faceToRight():void {
			if (scaleX > 0) {
				scaleX = -scaleX;
			}
		}
		
		public function set onGround(value:Boolean):void {
			var event:Event = null;
			if (onGround != value ) {
				event = new Event(value ? ON_GROUND : OFF_GROUND);
//			} else if (onGround == true && value == false) {
//				trace("---------> jump");
			}
//			if (this is MainCharacterView) {
//				trace(value ? "ground" : "in air");
//			}
			_onGround = value;
			if (event != null) {
//				trace("-----> on Ground");
				dispatchEvent(event);
			}
		}
		
	}
}